﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;

using ComponentFactory.Krypton.Toolkit;

using Microsoft.Build.Evaluation;

using SceneEngine;

namespace SceneEditor.UI
{
    public partial class EditorSplash : KryptonForm
    {
        private string projectFolder;

        private string projectPath;
        private string contentPath;
        private string scenePath;

        private bool newScene;

        private List<string> sceneNames;

        public bool NewScene
        {
            get { return newScene; }
            set { newScene = value; }
        }

        public string ProjectPath
        {
            get { return projectPath; }
        }
        public string ContentPath
        {
            get { return contentPath; }
        }
        public string ScenePath
        {
            get { return scenePath; }
        }

        public EditorSplash()
        {
            InitializeComponent();
        }

        private string FormatDateTime(DateTime dateTime)
        {
            return dateTime.ToString("ddd MMM d HH:mm") + 
                dateTime.ToString(" tt").ToLower();
        }

        private void EditorSplash_Load(object sender, EventArgs e)
        {
            string directoryPath = string.Empty;

            if (Preferences.Default.ProjectDirectory == "DefaultProjectDirectory")
            {
                directoryPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
                directoryPath = Path.Combine(directoryPath, "Visual Studio 2010\\Projects");

                if (Directory.Exists(directoryPath))
                {
                    Preferences.Default.ProjectDirectory = directoryPath;
                    Preferences.Default.Save();
                }
            }
            else
            {
                directoryPath = Preferences.Default.ProjectDirectory;
            }

            if (Directory.Exists(directoryPath))
            {
                lblDirectoryPath.Text = directoryPath;
                SetUpProjects();
            }
            else
            {
                lblDirectoryPath.Text = string.Empty;
            }
        }

        private void SetUpForm()
        {
            KryptonListItem selectedItem = lbProjects.SelectedItem as KryptonListItem;
            string[] tag = selectedItem.Tag as string[];

            projectFolder = Path.GetDirectoryName(tag[1] as string);

            DateTime lastUpdated = File.GetLastWriteTime(tag[0]);
            DateTime created = File.GetCreationTime(tag[0]);

            lblName.Text = Path.GetFileNameWithoutExtension(tag[0]);
            lblUpdated.Text = FormatDateTime(lastUpdated);
            lblCreated.Text = FormatDateTime(created);

            SetUpScenes(tag);

            string projectDirectory = Path.GetDirectoryName(tag[0]);
            string thumbnailPath = Path.Combine(projectDirectory, "GameThumbnail.png");

            if (File.Exists(thumbnailPath))
            {
                pbThumbnail.Image = Image.FromFile(thumbnailPath);
            }
        }

        private void SetUpScenes(string[] tag)
        {
            List<string> sceneFiles = FindSceneFiles(tag[1]);
            lbScenes.Items.Clear();

            sceneNames = new List<string>();

            foreach (string scene in sceneFiles)
            {
                string sceneName = Path.GetFileNameWithoutExtension(scene);

                KryptonListItem sceneItem = new KryptonListItem(sceneName);
                sceneItem.Tag = scene;

                lbScenes.Items.Add(sceneItem);
                sceneNames.Add(sceneName);
            }
        }
        private void SetUpProjects()
        {
            lbProjects.Items.Clear();

            string directoryPath = lblDirectoryPath.Text;

            if (string.IsNullOrEmpty(directoryPath))
            {
                return;
            }

            string[] projectDirectorys = Directory.GetDirectories(directoryPath);

            foreach (string directory in projectDirectorys)
            {
                string[] projectPaths = FindProjectFiles(directory);

                if (projectPaths == null)
                {
                    continue;
                }

                if (string.IsNullOrEmpty(projectPaths[0]) || string.IsNullOrEmpty(projectPaths[1]))
                {
                    continue;
                }

                string projectDirectory = Path.GetDirectoryName(projectPaths[0]);

                KryptonListItem item = new KryptonListItem(Path.GetFileNameWithoutExtension(projectPaths[0]));
                item.Tag = new string[] { projectPaths[0], projectPaths[1] };

                lbProjects.Items.Add(item);
            }

            if (lbProjects.Items.Count > 0)
            {
                lbProjects.SelectedIndex = 0;
                SetUpForm();
            }
        }

        private List<string> FindSceneFiles(string directory)
        {
            Stack<string> stack = new Stack<string>();

            List<string> sceneFiles = new List<string>();

            stack.Push(Path.GetDirectoryName(directory));

            while (stack.Count > 0)
            {
                string dir = stack.Pop();

                List<string> files = new List<string>();
                files.AddRange(Directory.GetFiles(dir, "*.scn"));

                foreach (string fileName in files)
                    sceneFiles.Add(fileName);

                foreach (string dn in Directory.GetDirectories(dir))
                {
                    stack.Push(dn);
                }
            }
            return sceneFiles;
        }
        private string[] FindProjectFiles(string directory)
        {
            Stack<string> stack = new Stack<string>();

            string[] paths = new string[2];

            string projectFilePath = string.Empty;
            string contentProjectPath = string.Empty;

            stack.Push(directory);

            while (stack.Count > 0)
            {
                string dir = stack.Pop();

                try
                {
                    foreach (string fileName in Directory.GetFiles(dir, "*.*"))
                    {
                        if (Path.GetExtension(fileName) == ".csproj")
                            paths[0] = fileName;
                        else if (Path.GetExtension(fileName) == ".contentproj")
                            paths[1] = fileName;
                    }
                }
                catch 
                {

                }

                if (!string.IsNullOrEmpty(paths[0]) && !string.IsNullOrEmpty(paths[1]))
                    return paths;

                try
                {
                    string[] directories = Directory.GetDirectories(dir);

                    foreach (string dn in directories)
                    {
                        stack.Push(dn);
                    }
                }
                catch
                {

                }
            }
            return null;
        }

        private void lbProjects_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lbProjects.SelectedIndex == -1)
            {
                return;
            }

            SetUpForm();
        }

        private void btnEdit_Click(object sender, EventArgs e)
        {
            if (lbProjects.SelectedIndex == -1)
            {
                MessageBox.Show("Please Select a project to load");
                return;
            }
            if (lbScenes.SelectedIndex == -1)
            {
                MessageBox.Show("Please Select a scene to load");
                return;
            }

            KryptonListItem selectedProject = lbProjects.SelectedItem as KryptonListItem;
            KryptonListItem selectedScene = lbScenes.SelectedItem as KryptonListItem;

            string[] tag = selectedProject.Tag as string[];

            this.projectPath = tag[0];
            this.contentPath = tag[1];

            this.scenePath = selectedScene.Tag as string;

            this.DialogResult = DialogResult.OK;
            this.Close();
        }

        private void btnChangeDirectory_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog folderDialog = new FolderBrowserDialog();
            folderDialog.SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

            if (folderDialog.ShowDialog() == DialogResult.OK)
            {
                string directoryPath = folderDialog.SelectedPath;

                if (!Directory.Exists(directoryPath))
                {
                    lblDirectoryPath.Text = string.Empty;
                    return;
                }

                lblDirectoryPath.Text = directoryPath;

                Preferences.Default.ProjectDirectory = directoryPath;
                Preferences.Default.Save();
            }

            SetUpProjects();
        }

        private void btnAddScene_Click(object sender, EventArgs e)
        {
            TextEntryForm textForm = new TextEntryForm();
            textForm.Text = "Choose a name for your scene";
            textForm.lblText.Text = "Name";

            bool suitableNameChosen = false;

            while (!suitableNameChosen)
            {
                DialogResult textResult = textForm.ShowDialog();

                if (textResult != DialogResult.OK)
                    return;

                if (sceneNames.Contains(textForm.tbText.Text))
                    MessageBox.Show("A scene with that name already exists. Please choose a different name");
                else
                    suitableNameChosen = true;
            }

            KryptonListItem selectedItem = lbProjects.SelectedItem as KryptonListItem;
            string[] tag = selectedItem.Tag as string[];

            string directory = Path.GetDirectoryName(tag[1]);
            directory = Path.Combine(directory, "Scenes");

            if (!Directory.Exists(directory))
                Directory.CreateDirectory(directory);

            string scenePath = Path.Combine(directory, textForm.tbText.Text + ".scn");

            if (File.Exists(scenePath))
            {
                DialogResult messageResult = MessageBoxHelper.ShowFileExists();

                if (messageResult != DialogResult.Yes)
                    return;
            }

            Scene scene = new Scene();
            scene.Save(scenePath);

            AddSceneToContentProject(scenePath, tag[1]);

            KryptonListItem sceneItem = new KryptonListItem(textForm.tbText.Text);
            sceneItem.Tag = scenePath;

            lbScenes.Items.Add(sceneItem);

            this.scenePath = scenePath;
            this.newScene = true;

            KryptonListItem selectedProject = lbProjects.SelectedItem as KryptonListItem;
            string[] projectTag = selectedProject.Tag as string[];

            this.projectPath = projectTag[0];
            this.contentPath = projectTag[1];

            this.DialogResult = DialogResult.OK;
            this.Close();
        }
        private void btnRemoveScene_Click(object sender, EventArgs e)
        {
            if (lbProjects.SelectedIndex < 0)
            {
                MessageBox.Show("Please select a project from the list of projects", "Selection Error", MessageBoxButtons.OK, MessageBoxIcon.None);
                return;
            }
            if (lbScenes.SelectedIndex < 0)
            {
                MessageBox.Show("Please select a scene from the list of scenes", "Selection Error", MessageBoxButtons.OK, MessageBoxIcon.None);
                return;
            }

            KryptonListItem selectedItem = lbProjects.SelectedItem as KryptonListItem;
            string[] tag = selectedItem.Tag as string[];

            string scenePath = (lbScenes.SelectedItem as KryptonListItem).Tag as string;

            if (File.Exists(scenePath))
            {
                DialogResult messageResult = MessageBox.Show(string.Format("Are you sure you would like to delete {0}?", Path.GetFileName(scenePath)),
                    "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);

                if (messageResult != DialogResult.Yes)
                    return;
            }


            File.Delete(scenePath);
            RemoveSceneFromContentProject(scenePath, tag[1]);

            lbScenes.Items.RemoveAt(lbScenes.SelectedIndex);

            if (lbScenes.Items.Count > 0)
                lbScenes.SelectedIndex = 0;
            else
                lbScenes.SelectedIndex = -1;
        }

        private void btnRefreshProjects_Click(object sender, EventArgs e)
        {
            SetUpProjects();
        }
        private void btnRefreshScene_Click(object sender, EventArgs e)
        {
            if (lbProjects.SelectedIndex == -1)
                return;

            KryptonListItem selectedItem = lbProjects.SelectedItem as KryptonListItem;
            string[] tag = selectedItem.Tag as string[];

            SetUpScenes(tag);
        }

        public void AddSceneToContentProject(string filePath, string contentPath)
        {
            Project contentProject = EditorGlobals.GetProject(contentPath);

            string name = Path.GetFileNameWithoutExtension(filePath);
            string link = Path.GetFileName(filePath);
            string directoryName = Path.GetFileName(Path.GetDirectoryName(filePath));
            string path = "Scenes";
            path = Path.Combine(path, link);

            ProjectItem newItem = contentProject.AddItem("Compile", path)[0];
            newItem.SetMetadataValue("Name", name);
            newItem.SetMetadataValue("Importer", "EngineXmlImporter");
            newItem.SetMetadataValue("Processor", "EngineSceneProcessor");

            contentProject.Save();
        }

        public void RemoveSceneFromContentProject(string filePath, string contentPath)
        {
            Project contentProject = EditorGlobals.GetProject(contentPath);

            string directory = Path.GetFileName(Path.GetDirectoryName(filePath));
            string relativePath = Path.Combine(directory, Path.GetFileName(filePath));

            foreach (ProjectItem projectItem in contentProject.GetItems("Compile"))
            {
                if (projectItem.EvaluatedInclude == relativePath)
                {
                    contentProject.RemoveItem(projectItem);
                    break;
                }
            }

            contentProject.Save();
        }
    }
}
